import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:crypto/crypto.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:ride_rex/net/common_global_url.dart';
import 'package:ride_rex/net/common_net.dart';
import 'package:ride_rex/net/common_net_builder.dart';
import 'package:ride_rex/service/user_service.dart';
import 'package:ylm_ui_kit/ylm_ui_kit.dart';

/// 打点请求头key统一传参
class LMLogHeadersKey {
  static const String data = "data";
  static const String logType = "log_type";
  static const String subtype = "subtype";
  static const String behavior = "behavior";
  static const String deviceId = "device-id";
  static const String androidId = "android_id";
  static const String userId = "user_id";
  static const String pkg = "pkg";
  static const String chnId = "chn_id";
  static const String ver = "ver";
  static const String platform = "platform";
  static const String model = "model";
  static const String pVer = "p_ver";
  static const String lanId = "lan_id";
  static const String secId = "sec_id";
  static const String utmSource = "utm_source";
  static const String afAdgroupId = "af_adgroup_id";
  static const String afAdset = "af_adset";
  static const String afAdsetId = "af_adset_id";
  static const String afStatus = "af_status";
  static const String afAgency = "af_agency";
  static const String afChannel = "af_channel";
  static const String campaign = "campaign";
  static const String campaignId = "campaign_id";
  static const String country = "country";
  static const String sysLan = "sys_lan";
}

/// 打点中所有涉及到的页面KEY
class LogPages {
  ///  key值（字符串）参考下面的埋点事件
}

class LMLogManager {
  LMLogManager._();

  static const String _event = 'event';
  static const String _tm = 'tm';
  static const String _page = 'page';
  static const String _subPage = 'subPage';
  static const String _terPage = 'terPage';
  static const String _broadcasterId = 'broadcasterId';
  static const String _duration = 'duration';

  static void stat({
    String? page,
    String? subPage,
    String? terPage,
    String? broadcasterId,
  }) {
    var map = <String, dynamic>{};
    // ⚠️page传入下方的埋点事件page值
    if (page != null) {
      map[_page] = page;
    }
    if (subPage != null) {
      map[_subPage] = subPage;
    }
    if (terPage != null) {
      map[_terPage] = terPage;
    }
    if (broadcasterId != null) {
      map[_broadcasterId] = broadcasterId;
    }
    map[_duration] = 0;
    map[_event] = 'pv';
    map[_tm] = DateTime.now().millisecondsSinceEpoch;

    if (kDebugMode) {
      Log.log('LogPvMgr - $map');
    }
    LMLogManger().putLog(LMLogType.globalBehavior, map);
  }
}

/// 打点类型
enum LMLogType {
  globalBehavior('event', 'global_behavior', 'event'),
  clickEvent("event", "click", "event");

  final String logType;
  final String subType;
  final String behavior;

  const LMLogType(this.logType, this.subType, this.behavior);
}

// 打点管理
class LMLogManger {
  static final LMLogManger _instance = LMLogManger._internal();
  factory LMLogManger() {
    return _instance;
  }
  LMLogManger._internal();

  static const String tag = "LogManger"; // 日志标签
  static const int limitSize = 20; // 打点任务最多缓存长度
  static int _serialId = 0;
  // 每次启动App该值会修改
  static String launcherId = _md5('${DateTime.now().millisecondsSinceEpoch}${DeviceInfoUtils().deviceId}');
  final List<Map<String, dynamic>> cacheList = [];
  bool _isWaitingForSend = false; // 是否需要延迟上报

  static String _md5(String value) {
    var bytes = utf8.encode(value); // data being hashed
    var digest = md5.convert(bytes);
    return digest.toString();
  }

  /// 上报日志
  void putLog(LMLogType logType, Map<String, dynamic>? event) {
    if (logType.logType.isEmpty ||
        logType.subType.isEmpty ||
        logType.behavior.isEmpty ||
        event == null ||
        event.isEmpty) {
      return;
    }
    cacheList.insert(0, event);
    sendDelayed();
  }

  /// 延时发送日志
  void sendDelayed() {
    if (_isWaitingForSend) {
      return;
    }
    _isWaitingForSend = true;
    Timer(const Duration(milliseconds: 2000), () {
      _isWaitingForSend = false;
      sendLog(false);
    });
  }

  /// 发日志打点
  void sendLog(bool forceUploadAll) {
    try {
      List<Map<String, dynamic>> sendList = [];
      if (cacheList.isEmpty) {
        return;
      } else if (cacheList.length >= limitSize && !forceUploadAll) {
        sendList.addAll(cacheList.sublist(0, limitSize));
        cacheList.removeRange(0, limitSize);
      } else {
        sendList.addAll(cacheList);
        cacheList.clear();
      }
      _doUpload(sendList, true);
    } catch (e) {
      if (kDebugMode) {
        print(e);
      }
    }
  }

  /// 立马发送日志
  void putLogRightNow(LMLogType logType, Map<String, dynamic>? event) {
    if (logType.logType.isEmpty ||
        logType.subType.isEmpty ||
        logType.behavior.isEmpty ||
        event == null ||
        event.isEmpty) {
      return;
    }
    List<Map<String, dynamic>> list = [];
    list.add(event);

    _doUpload(list, false);
  }

  /// 执行上传
  Future<void> _doUpload(List<Map<String, dynamic>> sendList, bool isContinue) async {
    final BaseOptions baseOptions = BaseOptions(
      baseUrl: CommonGlobalUrl.apiLog,
      connectTimeout: const Duration(seconds: 30),
      receiveTimeout: const Duration(seconds: 30),
      headers: await CommonNet.builder.initHeaders(),
    );
    final Dio dio = Dio(baseOptions);
    Map<String, dynamic> data = _buildData(sendList);
    try {
      await dio.post(CommonGlobalUrl.log, data: [data]);
      if (isContinue) sendDelayed();
    } catch (e) {
      print(e);
    }
  }

  Map<String, dynamic> _buildData(List<Map<String, dynamic>> eventList) {
    String platform = '';
    String model = DeviceInfoUtils().deviceModel;
    if (Platform.isAndroid) {
      platform = 'Android';
    } else if (Platform.isIOS) {
      platform = 'iOS';
    }
    Map<String, dynamic> itemData = {};
    itemData[LMLogHeadersKey.data] = eventList;
    itemData[LMLogHeadersKey.logType] = 'event';
    itemData[LMLogHeadersKey.subtype] = 'global_behavior';
    itemData[LMLogHeadersKey.behavior] = 'event';
    itemData[LMLogHeadersKey.deviceId] = DeviceInfoUtils().deviceId;
    itemData[LMLogHeadersKey.userId] = UserService.instance.userId;
    itemData[LMLogHeadersKey.pkg] = PackageInfoUtils().packageName;
    itemData[LMLogHeadersKey.chnId] = '';
    itemData[LMLogHeadersKey.ver] = PackageInfoUtils().version;
    itemData[LMLogHeadersKey.platform] = platform;
    itemData[LMLogHeadersKey.model] = model;
    itemData[LMLogHeadersKey.pVer] = PackageInfoUtils().build;
    itemData[LMLogHeadersKey.lanId] = launcherId;
    itemData[LMLogHeadersKey.secId] = _serialId++;
    itemData[LMLogHeadersKey.sysLan] = DeviceInfoUtils().deviceLanguageCode;
    itemData[LMLogHeadersKey.country] = UserService.instance.notifierOfMineInfo.value.country;
    itemData["tm"] = DateTime.now().millisecondsSinceEpoch;
    return itemData;
  }
}
